package org.zjvis.datascience.common.enums;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.zjvis.datascience.common.model.ApiResultCode;

import java.util.List;

/**
 * @description 机器学习算子节点验证枚举类
 * @date 2021-11-15
 */
public enum ValidateConfigEnum {
    DBSCAN((jsonObject, errorCode) -> {
        //距离阈值
        String eps = jsonObject.getString("eps");
        //样本阈值
        String min_samples = jsonObject.getString("min_samples");
        if (isDoubleBiggerThanZero(eps) && isIntBiggerThanZero(min_samples)) {
            return true;
        }
        errorCode.add(ApiResultCode.NUMERIC_VALIDATE_FAIL);
        return false;
    }),

    KMEANS((jsonObject, errorCode) -> {
        //聚类维度
        String k = jsonObject.getString("k");
        //最大迭代数
        String min_samples = jsonObject.getString("max_iter");
        //重心最小分数
        String min_frac = jsonObject.getString("min_frac");
        if (isIntBiggerThanZero(k) && isIntBiggerThanZero(min_samples) && isDoubleBiggerThanZero(
                min_frac)) {
            Double minFrac = Double.valueOf(min_frac);
            if (minFrac <= 1) return true;
        }
        errorCode.add(ApiResultCode.NUMERIC_VALIDATE_FAIL);
        return false;
    }),

    //  LINEARREGRE无数值类型校验,

    PCA_DENSE((jsonObject, errorCode) -> {
        return dimensionReductionVerify(jsonObject, errorCode);
    }),

    TSNE((jsonObject, errorCode) -> {
        return dimensionReductionVerify(jsonObject, errorCode);
    }),

    LLE((jsonObject, errorCode) -> {
        if (!dimensionReductionVerify(jsonObject, errorCode)) {
            return false;
        }
        String neighbors = jsonObject.getString("neighbors");
        if (!isIntBiggerThanZero(neighbors)) {
            errorCode.add(ApiResultCode.NUMERIC_VALIDATE_FAIL);
            return false;
        }
        return true;
    }),

    //  STAT_ANOMALY无数值类型校验,

    ISO_FOREST((jsonObject, errorCode) -> {
        //树的数量
        String n_estimators = jsonObject.getString("n_estimators");
        //样本比例
        String max_samples = jsonObject.getString("max_samples");
        //异常点比例
        String contamination = jsonObject.getString("contamination");
        if (isIntBiggerThanZero(n_estimators) && isDoubleBiggerThanZero(max_samples)
                && isDoubleBiggerThanZero(contamination)) {
            Double samples = Double.valueOf(max_samples);
            if (samples > 1) {
                errorCode.add(ApiResultCode.ISO_FOREST_PARAM_SAMPLES_ILLEGAL);
                return false;
            }
            Double con = Double.valueOf(contamination);
            if (con >= 0.5) {
                errorCode.add(ApiResultCode.ISO_FOREST_PARAM_CONTAMINATION_ILLEGAL);
                return false;
            }
            return true;
        }
        errorCode.add(ApiResultCode.NUMERIC_VALIDATE_FAIL);
        return false;
    }),

    LOGREGRE((jsonObject, errorCode) -> {
        //最大迭代数
        String min_samples = jsonObject.getString("max_iter");
        //容忍度
        String tolerance = jsonObject.getString("tolerance");
        if (isIntBiggerThanZero(min_samples) && isDoubleBiggerThanZero(tolerance)) {
            return true;
        }
        errorCode.add(ApiResultCode.NUMERIC_VALIDATE_FAIL);
        return false;
    }),

    FP_GROWTH((jsonObject, errorCode) -> {
        //最大迭代数
        String min_frequency = jsonObject.getString("min_frequency");
        //容忍度
        String min_support = jsonObject.getString("min_support");
        if (isDoubleBiggerThanZero(min_frequency) && isDoubleBiggerThanZero(min_support)) {
            return true;
        }
        errorCode.add(ApiResultCode.NUMERIC_VALIDATE_FAIL);
        return false;
    }),

    PREFIX_SPAN((jsonObject, errorCode) -> {
        //最小频率
        String min_frequency = jsonObject.getString("min_frequency");
        //最小支持度
        String min_support = jsonObject.getString("min_support");
        if (isDoubleBiggerThanZero(min_frequency) && isDoubleBiggerThanZero(min_support)) {
            return true;
        }
        errorCode.add(ApiResultCode.NUMERIC_VALIDATE_FAIL);
        return false;
    }),

    SAMPLE((jsonObject, errorCode) -> {
        if (jsonObject == null) {
            errorCode.add(ApiResultCode.SYS_ERROR);
            return false;
        }
        //样本数量，限制1-100_0000
        String count = jsonObject.getString("count");
        if (ValidateConfigEnum.isIntBiggerThanZero(count)) {
            Integer integer = Integer.valueOf(count);
            if (integer <= 100_0000) {
                return true;
            }
        }
        errorCode.add(ApiResultCode.SAMPLE_PARAM_COUNT_ILLEGAL);
        return false;
    });

    private ValidateConfig validateConfig;

    //大于零的整数型
    public static boolean isIntBiggerThanZero(String str) {
        try {
            Integer number = Integer.valueOf(str);
            return number > 0 ? true : false;
        } catch (Exception e) {
            return false;
        }
    }

    //大于零的数值型
    public static boolean isDoubleBiggerThanZero(String str) {
        try {
            Double number = Double.valueOf(str);
            return number > 0 ? true : false;
        } catch (Exception e) {
            return false;
        }
    }

    //降维参数校验
    public static boolean dimensionReductionVerify(JSONObject jsonObject,
                                                   List<ApiResultCode> errorCode) {
        //降维的维度
        String dimension_num = jsonObject.getString("dimension_num");
        //特征列
        JSONArray feature_cols = jsonObject.getJSONArray("feature_cols");
        if (isIntBiggerThanZero(dimension_num)) {
            Integer number = Integer.valueOf(dimension_num);
            if (number <= feature_cols.size()) {
                return true;
            }
        }
        errorCode.add(ApiResultCode.DIMENSION_REDUCTION_VALIDATE_FAIL);
        return false;
    }

    public boolean validate(JSONObject jsonObject, List<ApiResultCode> errorCode) {
        return validateConfig.validate(jsonObject, errorCode);
    }

    ValidateConfigEnum(ValidateConfig validateConfig) {
        this.validateConfig = validateConfig;
    }

    private interface ValidateConfig {
        boolean validate(JSONObject jsonObject, List<ApiResultCode> errorCode);
    }
}
